home *** CD-ROM | disk | FTP | other *** search
/ GameStar 2004 April / Gamestar_61_2004-04_dvdb.iso / DVDStar / Editace / hltp.exe / {app} / Source Code / Zoners Half-Life Tools / hlvis / flow.cpp next >
C/C++ Source or Header  |  2002-06-10  |  40KB  |  1,399 lines

  1. #include "vis.h"
  2.  
  3. // =====================================================================================
  4. //  CheckStack
  5. // =====================================================================================
  6. #ifdef USE_CHECK_STACK
  7. static void     CheckStack(const leaf_t* const leaf, const threaddata_t* const thread)
  8. {
  9.     pstack_t*       p;
  10.  
  11.     for (p = thread->pstack_head.next; p; p = p->next)
  12.     {
  13.         if (p->leaf == leaf)
  14.             Error("CheckStack: leaf recursion");
  15.     }
  16. }
  17. #endif
  18.  
  19. // =====================================================================================
  20. //  AllocStackWinding
  21. // =====================================================================================
  22. inline static winding_t* AllocStackWinding(pstack_t* const stack)
  23. {
  24.     int             i;
  25.  
  26.     for (i = 0; i < 3; i++)
  27.     {
  28.         if (stack->freewindings[i])
  29.         {
  30.             stack->freewindings[i] = 0;
  31.             return &stack->windings[i];
  32.         }
  33.     }
  34.  
  35.     Error("AllocStackWinding: failed");
  36.  
  37.     return NULL;
  38. }
  39.  
  40. // =====================================================================================
  41. //  FreeStackWinding
  42. // =====================================================================================
  43. inline static void     FreeStackWinding(const winding_t* const w, pstack_t* const stack)
  44. {
  45.     int             i;
  46.  
  47.     i = w - stack->windings;
  48.  
  49.     if (i < 0 || i > 2)
  50.         return;                                            // not from local
  51.  
  52.     if (stack->freewindings[i])
  53.         Error("FreeStackWinding: allready free");
  54.     stack->freewindings[i] = 1;
  55. }
  56.  
  57. // =====================================================================================
  58. //  ChopWinding
  59. // =====================================================================================
  60. inline winding_t*      ChopWinding(winding_t* const in, pstack_t* const stack, const plane_t* const split)
  61. {
  62.     vec_t           dists[128];
  63.     int             sides[128];
  64.     int             counts[3];
  65.     vec_t           dot;
  66.     int             i;
  67.     vec3_t          mid;
  68.     winding_t*      neww;
  69.  
  70.     counts[0] = counts[1] = counts[2] = 0;
  71.  
  72.     if (in->numpoints > (sizeof(sides) / sizeof(*sides)))
  73.     {
  74.         Error("Winding with too many sides!");
  75.     }
  76.  
  77.     // determine sides for each point
  78.     for (i = 0; i < in->numpoints; i++)
  79.     {
  80.         dot = DotProduct(in->points[i], split->normal);
  81.         dot -= split->dist;
  82.         dists[i] = dot;
  83.         if (dot > ON_EPSILON)
  84.         {
  85.             sides[i] = SIDE_FRONT;
  86.         }
  87.         else if (dot < -ON_EPSILON)
  88.         {
  89.             sides[i] = SIDE_BACK;
  90.         }
  91.         else
  92.         {
  93.             sides[i] = SIDE_ON;
  94.         }
  95.         counts[sides[i]]++;
  96.     }
  97.  
  98.     if (!counts[1])
  99.     {
  100.         return in;                                         // completely on front side
  101.     }
  102.  
  103.     if (!counts[0])
  104.     {
  105.         FreeStackWinding(in, stack);
  106.         return NULL;
  107.     }
  108.  
  109.     sides[i] = sides[0];
  110.     dists[i] = dists[0];
  111.  
  112.     neww = AllocStackWinding(stack);
  113.  
  114.     neww->numpoints = 0;
  115.  
  116.     for (i = 0; i < in->numpoints; i++)
  117.     {
  118.         vec_t* p1 = in->points[i];
  119.  
  120.         if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING)
  121.         {
  122.             Warning("ChopWinding : rejected(1) due to too many points\n");
  123.             FreeStackWinding(neww, stack);
  124.             return in;                                     // can't chop -- fall back to original
  125.         }
  126.  
  127.         if (sides[i] == SIDE_ON)
  128.         {
  129.             VectorCopy(p1, neww->points[neww->numpoints]);
  130.             neww->numpoints++;
  131.             continue;
  132.         }
  133.         else if (sides[i] == SIDE_FRONT)
  134.         {
  135.             VectorCopy(p1, neww->points[neww->numpoints]);
  136.             neww->numpoints++;
  137.         }
  138.  
  139.         if ((sides[i + 1] == SIDE_ON) | (sides[i + 1] == sides[i])) // | instead of || for branch optimization
  140.         {
  141.             continue;
  142.         }
  143.  
  144.         if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING)
  145.         {
  146.             Warning("ChopWinding : rejected(2) due to too many points\n");
  147.             FreeStackWinding(neww, stack);
  148.             return in;                                     // can't chop -- fall back to original
  149.         }
  150.  
  151.         // generate a split point
  152.         {
  153.             unsigned tmp = i + 1;
  154.             if (tmp >= in->numpoints)
  155.             {
  156.                 tmp = 0;
  157.             }
  158.             const vec_t* p2 = in->points[tmp];
  159.  
  160.             dot = dists[i] / (dists[i] - dists[i + 1]);
  161.  
  162.             const vec_t* normal = split->normal;
  163.             const vec_t dist = split->dist;
  164.             unsigned int j;
  165.             for (j = 0; j < 3; j++)
  166.             {                                                  // avoid round off error when possible
  167.                 if (normal[j] < (1.0 - NORMAL_EPSILON))
  168.                 {
  169.                     if (normal[j] > (-1.0 + NORMAL_EPSILON))
  170.                     {
  171.                         mid[j] = p1[j] + dot * (p2[j] - p1[j]);
  172.                     }
  173.                     else
  174.                     {
  175.                         mid[j] = -dist;
  176.                     }
  177.                 }
  178.                 else
  179.                 {
  180.                     mid[j] = dist;
  181.                 }
  182.             }
  183.         }
  184.  
  185.         VectorCopy(mid, neww->points[neww->numpoints]);
  186.         neww->numpoints++;
  187.     }
  188.  
  189.     // free the original winding
  190.     FreeStackWinding(in, stack);
  191.  
  192.     return neww;
  193. }
  194.  
  195. // =====================================================================================
  196. //  AddPlane
  197. // =====================================================================================
  198. #ifdef RVIS_LEVEL_2
  199. inline static void AddPlane(pstack_t* const stack, const plane_t* const split)
  200. {
  201.     int     j;
  202.     
  203.     if (stack->clipPlaneCount)
  204.     {
  205.         for (j = 0; j < stack->clipPlaneCount; j++)
  206.         {
  207.             if (fabs((stack->clipPlane[j]).dist - split->dist) <= EQUAL_EPSILON &&
  208.                 VectorCompare((stack->clipPlane[j]).normal, split->normal))
  209.             {
  210.                 return;
  211.             }
  212.         }
  213.     }
  214.     stack->clipPlane[stack->clipPlaneCount] = *split;
  215.     stack->clipPlaneCount++;
  216. }
  217. #endif
  218.  
  219. // =====================================================================================
  220. //  ClipToSeperators
  221. //      Source, pass, and target are an ordering of portals.
  222. //      Generates seperating planes canidates by taking two points from source and one
  223. //      point from pass, and clips target by them.
  224. //      If the target argument is NULL, then a list of clipping planes is built in
  225. //      stack instead.
  226. //      If target is totally clipped away, that portal can not be seen through.
  227. //      Normal clip keeps target on the same side as pass, which is correct if the
  228. //      order goes source, pass, target.  If the order goes pass, source, target then
  229. //      flipclip should be set.
  230. // =====================================================================================
  231. inline static winding_t* ClipToSeperators(
  232.     const winding_t* const source,
  233.     const winding_t* const pass, 
  234.     winding_t* const a_target,
  235.     const bool flipclip, 
  236.     pstack_t* const stack)
  237. {
  238.     int             i, j, k, l;
  239.     plane_t         plane;
  240.     vec3_t          v1, v2;
  241.     float           d;
  242.     int             counts[3];
  243.     bool            fliptest;
  244.     winding_t*      target = a_target;
  245.  
  246.     const unsigned int numpoints = source->numpoints;
  247.  
  248.     // check all combinations       
  249.     for (i=0, l=1; i < numpoints; i++, l++)
  250.     {
  251.         if (l == numpoints)
  252.         {
  253.             l = 0;
  254.         }
  255.  
  256.         VectorSubtract(source->points[l], source->points[i], v1);
  257.  
  258.         // fing a vertex of pass that makes a plane that puts all of the
  259.         // vertexes of pass on the front side and all of the vertexes of
  260.         // source on the back side
  261.         for (j = 0; j < pass->numpoints; j++)
  262.         {
  263.             VectorSubtract(pass->points[j], source->points[i], v2);
  264.             CrossProduct(v1, v2, plane.normal);
  265.             if (VectorNormalize(plane.normal) < ON_EPSILON)
  266.             {
  267.                 continue;
  268.             }
  269.             plane.dist = DotProduct(pass->points[j], plane.normal);
  270.  
  271.             // find out which side of the generated seperating plane has the
  272.             // source portal
  273.             fliptest = false;
  274.             for (k = 0; k < numpoints; k++)
  275.             {
  276.                 if ((k == i) | (k == l)) // | instead of || for branch optimization
  277.                 {
  278.                     continue;
  279.                 }
  280.                 d = DotProduct(source->points[k], plane.normal) - plane.dist;
  281.                 if (d < -ON_EPSILON)
  282.                 {                                          // source is on the negative side, so we want all
  283.                     // pass and target on the positive side
  284.                     fliptest = false;
  285.                     break;
  286.                 }
  287.                 else if (d > ON_EPSILON)
  288.                 {                                          // source is on the positive side, so we want all
  289.                     // pass and target on the negative side
  290.                     fliptest = true;
  291.                     break;
  292.                 }
  293.             }
  294.             if (k == numpoints)
  295.             {
  296.                 continue;                                  // planar with source portal
  297.             }
  298.  
  299.             // flip the normal if the source portal is backwards
  300.             if (fliptest)
  301.             {
  302.                 VectorSubtract(vec3_origin, plane.normal, plane.normal);
  303.                 plane.dist = -plane.dist;
  304.             }
  305.  
  306.             // if all of the pass portal points are now on the positive side,
  307.             // this is the seperating plane
  308.             counts[0] = counts[1] = counts[2] = 0;
  309.             for (k = 0; k < pass->numpoints; k++)
  310.             {
  311.                 if (k == j)
  312.                 {
  313.                     continue;
  314.                 }
  315.                 d = DotProduct(pass->points[k], plane.normal) - plane.dist;
  316.                 if (d < -ON_EPSILON)
  317.                 {
  318.                     break;
  319.                 }
  320.                 else if (d > ON_EPSILON)
  321.                 {
  322.                     counts[0]++;
  323.                 }
  324.                 else
  325.                 {
  326.                     counts[2]++;
  327.                 }
  328.             }
  329.             if (k != pass->numpoints)
  330.             {
  331.                 continue;                                  // points on negative side, not a seperating plane
  332.             }
  333.  
  334.             if (!counts[0])
  335.             {
  336.                 continue;                                  // planar with seperating plane
  337.             }
  338.  
  339.             // flip the normal if we want the back side
  340.             if (flipclip)
  341.             {
  342.                 VectorSubtract(vec3_origin, plane.normal, plane.normal);
  343.                 plane.dist = -plane.dist;
  344.             }
  345.  
  346.         if (target != NULL)
  347.         {
  348.             // clip target by the seperating plane
  349.             target = ChopWinding(target, stack, &plane);
  350.             if (!target)
  351.             {
  352.                 return NULL;                               // target is not visible
  353.             }
  354.         }
  355.         else
  356.         {
  357.             AddPlane(stack, &plane);
  358.         }
  359.  
  360. #ifdef RVIS_LEVEL_1
  361.             break; /* Antony was here */
  362. #endif
  363.         }
  364.     }
  365.  
  366.     return target;
  367. }
  368.  
  369. // =====================================================================================
  370. //  RecursiveLeafFlow
  371. //      Flood fill through the leafs
  372. //      If src_portal is NULL, this is the originating leaf
  373. // =====================================================================================
  374. inline static void     RecursiveLeafFlow(const int leafnum, const threaddata_t* const thread, const pstack_t* const prevstack)
  375. {
  376.     pstack_t        stack;
  377.     leaf_t*         leaf;
  378.  
  379.     leaf = &g_leafs[leafnum];
  380. #ifdef USE_CHECK_STACK
  381.     CheckStack(leaf, thread);
  382. #endif
  383.  
  384.     {
  385.         const unsigned offset = leafnum >> 3;
  386.         const unsigned bit = (1 << (leafnum & 7));
  387.     
  388.         // mark the leaf as visible
  389.         if (!(thread->leafvis[offset] & bit))
  390.         {
  391.             thread->leafvis[offset] |= bit;
  392.             thread->base->numcansee++;
  393.         }
  394.     }
  395.  
  396. #ifdef USE_CHECK_STACK
  397.     prevstack->next = &stack;
  398.     stack.next = NULL;
  399. #endif
  400.     stack.head = prevstack->head;
  401.     stack.leaf = leaf;
  402.     stack.portal = NULL;
  403. #ifdef RVIS_LEVEL_2
  404.     stack.clipPlaneCount = -1;
  405.     stack.clipPlane = NULL;
  406. #endif
  407.  
  408.     // check all portals for flowing into other leafs       
  409.     unsigned i;
  410.     portal_t** plist = leaf->portals;
  411.  
  412.     for (i = 0; i < leaf->numportals; i++, plist++)
  413.     {
  414.         portal_t* p = *plist;
  415.  
  416. #if ZHLT_ZONES
  417.         portal_t * head_p = stack.head->portal;
  418.         if (g_Zones->check(head_p->zone, p->zone))
  419.         {
  420.             continue;
  421.         }
  422. #endif
  423.  
  424.         {
  425.             const unsigned offset = p->leaf >> 3;
  426.             const unsigned bit = 1 << (p->leaf & 7);
  427.  
  428.             if (!(stack.head->mightsee[offset] & bit))
  429.             {
  430.                 continue;                                      // can't possibly see it
  431.             }
  432.             if (!(prevstack->mightsee[offset] & bit))
  433.             {
  434.                 continue;                                      // can't possibly see it
  435.             }
  436.         }
  437.  
  438.         // if the portal can't see anything we haven't allready seen, skip it
  439.         {
  440.             long* test;
  441.  
  442.             if (p->status == stat_done)
  443.             {
  444.                 test = (long*)p->visbits;
  445.             }
  446.             else
  447.             {
  448.                 test = (long*)p->mightsee;
  449.             }
  450.     
  451.             {
  452.                 const int bitlongs = g_bitlongs;
  453.  
  454.                 {
  455.                     long* prevmight = (long*)prevstack->mightsee;
  456.                     long* might = (long*)stack.mightsee;
  457.                 
  458.                     unsigned j;
  459.                     for (j = 0; j < bitlongs; j++, test++, might++, prevmight++)
  460.                     {
  461.                         (*might) = (*prevmight) & (*test);
  462.                     }
  463.                 }
  464.         
  465.                 {
  466.                     long* might = (long*)stack.mightsee;
  467.                     long* vis = (long*)thread->leafvis;
  468.                     unsigned j;
  469.                     for (j = 0; j < bitlongs; j++, might++, vis++)
  470.                     {
  471.                         if ((*might) & ~(*vis))
  472.                         {
  473.                             break;
  474.                         }
  475.                     }
  476.             
  477.                     if (j == g_bitlongs)
  478.                     {                                                  // can't see anything new
  479.                         continue;
  480.                     }
  481.                 }
  482.             }
  483.         }
  484.  
  485.         // get plane of portal, point normal into the neighbor leaf
  486.         stack.portalplane = &p->plane;
  487.         plane_t             backplane;
  488.         VectorSubtract(vec3_origin, p->plane.normal, backplane.normal);
  489.         backplane.dist = -p->plane.dist;
  490.  
  491.         if (VectorCompare(prevstack->portalplane->normal, backplane.normal))
  492.         {
  493.             continue;                                      // can't go out a coplanar face
  494.         }
  495.  
  496.         stack.portal = p;
  497. #ifdef USE_CHECK_STACK
  498.         stack.next = NULL;
  499. #endif
  500.         stack.freewindings[0] = 1;
  501.         stack.freewindings[1] = 1;
  502.         stack.freewindings[2] = 1;
  503.  
  504.         stack.pass = ChopWinding(p->winding, &stack, thread->pstack_head.portalplane);
  505.         if (!stack.pass)
  506.         {
  507.             continue;
  508.         }
  509.  
  510.         stack.source = ChopWinding(prevstack->source, &stack, &backplane);
  511.         if (!stack.source)
  512.         {
  513.             continue;
  514.         }
  515.  
  516.         if (!prevstack->pass)
  517.         {                                                  // the second leaf can only be blocked if coplanar
  518.             RecursiveLeafFlow(p->leaf, thread, &stack);
  519.             continue;
  520.         }
  521.  
  522.         stack.pass = ChopWinding(stack.pass, &stack, prevstack->portalplane);
  523.         if (!stack.pass)
  524.         {
  525.             continue;
  526.         }
  527.  
  528. #ifdef RVIS_LEVEL_2
  529.         if (stack.clipPlaneCount == -1)
  530.         {
  531.             stack.clipPlaneCount = 0;
  532.             stack.clipPlane = (plane_t*)alloca(sizeof(plane_t) * prevstack->source->numpoints * prevstack->pass->numpoints);
  533.  
  534.             ClipToSeperators(prevstack->source, prevstack->pass, NULL, false, &stack);
  535.             ClipToSeperators(prevstack->pass, prevstack->source, NULL, true, &stack);
  536.         }
  537.  
  538.         if (stack.clipPlaneCount > 0)
  539.         {
  540.             unsigned j;
  541.             for (j = 0; j < stack.clipPlaneCount && stack.pass != NULL; j++)
  542.             {
  543.                 stack.pass = ChopWinding(stack.pass, &stack, &(stack.clipPlane[j]));
  544.             }
  545.  
  546.             if (stack.pass == NULL)
  547.             continue;
  548.         }
  549. #else
  550.  
  551.         stack.pass = ClipToSeperators(stack.source, prevstack->pass, stack.pass, false, &stack);
  552.         if (!stack.pass)
  553.         {
  554.             continue;
  555.         }
  556.  
  557.         stack.pass = ClipToSeperators(prevstack->pass, stack.source, stack.pass, true, &stack);
  558.         if (!stack.pass)
  559.         {
  560.             continue;
  561.         }
  562. #endif
  563.  
  564.         if (g_fullvis)
  565.         {
  566.             stack.source = ClipToSeperators(stack.pass, prevstack->pass, stack.source, false, &stack);
  567.             if (!stack.source)
  568.             {
  569.                 continue;
  570.             }
  571.  
  572.             stack.source = ClipToSeperators(prevstack->pass, stack.pass, stack.source, true, &stack);
  573.             if (!stack.source)
  574.             {
  575.                 continue;
  576.             }
  577.         }
  578.  
  579.         // flow through it for real
  580.         RecursiveLeafFlow(p->leaf, thread, &stack);
  581.     }
  582.  
  583. #ifdef RVIS_LEVEL_2
  584. #if 0
  585.     if (stack.clipPlane != NULL)
  586.     {
  587.         free(stack.clipPlane);
  588.     }
  589. #endif
  590. #endif
  591. }
  592.  
  593. // =====================================================================================
  594. //  PortalFlow
  595. // =====================================================================================
  596. void            PortalFlow(portal_t* p)
  597. {
  598.     threaddata_t    data;
  599.     unsigned        i;
  600.  
  601.     if (p->status != stat_working)
  602.         Error("PortalFlow: reflowed");
  603.  
  604.     p->visbits = (byte*)calloc(1, g_bitbytes);
  605.  
  606.     memset(&data, 0, sizeof(data));
  607.     data.leafvis = p->visbits;
  608.     data.base = p;
  609.  
  610.     data.pstack_head.head = &data.pstack_head;
  611.     data.pstack_head.portal = p;
  612.     data.pstack_head.source = p->winding;
  613.     data.pstack_head.portalplane = &p->plane;
  614.     for (i = 0; i < g_bitlongs; i++)
  615.     {
  616.         ((long*)data.pstack_head.mightsee)[i] = ((long*)p->mightsee)[i];
  617.     }
  618.     RecursiveLeafFlow(p->leaf, &data, &data.pstack_head);
  619.  
  620. #ifdef ZHLT_NETVIS
  621.     p->fromclient = g_clientid;
  622. #endif
  623.     p->status = stat_done;
  624. #ifdef ZHLT_NETVIS
  625.     Flag_VIS_DONE_PORTAL(g_visportalindex);
  626. #endif
  627. }
  628.  
  629. // =====================================================================================
  630. //  SimpleFlood
  631. //      This is a rough first-order aproximation that is used to trivially reject some
  632. //      of the final calculations.
  633. // =====================================================================================
  634. static void     SimpleFlood(byte* const srcmightsee, const int leafnum, byte* const portalsee, unsigned int* const c_leafsee)
  635. {
  636.     unsigned        i;
  637.     leaf_t*         leaf;
  638.     portal_t*       p;
  639.  
  640.     {
  641.         const unsigned  offset = leafnum >> 3;
  642.         const unsigned  bit = (1 << (leafnum & 7));
  643.     
  644.         if (srcmightsee[offset] & bit)
  645.         {
  646.             return;
  647.         }
  648.         else
  649.         {
  650.             srcmightsee[offset] |= bit;
  651.         }
  652.     }
  653.  
  654.     (*c_leafsee)++;
  655.     leaf = &g_leafs[leafnum];
  656.  
  657.     for (i = 0; i < leaf->numportals; i++)
  658.     {
  659.         p = leaf->portals[i];
  660.         if (!portalsee[p - g_portals])
  661.         {
  662.             continue;
  663.         }
  664.         SimpleFlood(srcmightsee, p->leaf, portalsee, c_leafsee);
  665.     }
  666. }
  667.  
  668. #define PORTALSEE_SIZE (MAX_PORTALS*2)
  669. #ifdef SYSTEM_WIN32
  670. #pragma warning(push)
  671. #pragma warning(disable: 4100)                             // unreferenced formal parameter
  672. #endif
  673.  
  674. #ifdef HLVIS_MAXDIST
  675. // AJM: MVD
  676. // =====================================================================================
  677. //  BlockVis
  678. // =====================================================================================
  679. void            BlockVis(int unused)
  680. {
  681.     int i, j, k, l, m;
  682.     portal_t *p;
  683.     visblocker_t *v;
  684.     visblocker_t *v2;
  685.     leaf_t *leaf;
  686.     
  687.     while(1)
  688.     {
  689.         i = GetThreadWork();
  690.         if(i == -1)
  691.             break;
  692.  
  693.         v = &g_visblockers[i];
  694.  
  695.         // See which visblockers we need
  696.         for(j = 0; j < v->numnames; j++)
  697.         {
  698.             // Find visblocker
  699.             if(!(v2 = GetVisBlock(v->blocknames[j])))
  700.                 continue;
  701.  
  702.             // For each leaf in v2, eliminate visibility from v1
  703.             for(k = 0; k < v->numleafs; k++)
  704.             {
  705.                 leaf = &g_leafs[v->blockleafs[k]];
  706.                 
  707.                 for(l = 0; l < leaf->numportals; l++)
  708.                 {
  709.                     p = leaf->portals[l];
  710.                     
  711.                     for(m = 0; m < v2->numleafs; m++)
  712.                     {
  713.                         const unsigned offset = v2->blockleafs[m] >> 3;
  714.                         const unsigned bit = (1 << (v2->blockleafs[m] & 7));
  715.     
  716.                         p->mightsee[offset] &= ~bit;
  717.                     }
  718.                 }
  719.             }
  720.         }
  721.     }
  722. }
  723.  
  724. // AJM: MVD
  725. // =====================================================================================
  726. //  GetSplitPortal
  727. //      This function returns a portal on leaf1 that sucessfully seperates leaf1
  728. //      and leaf2
  729. // =====================================================================================
  730. static portal_t    *GetSplitPortal(leaf_t *leaf1, leaf_t *leaf2)
  731. {
  732.     int i, k, l;
  733.  
  734.     portal_t    *p1;
  735.     portal_t    *t;
  736.  
  737.     float check_dist;
  738.  
  739.     for(i = 0, p1 = leaf1->portals[0]; i < leaf1->numportals; i++, p1++)
  740.     {
  741.         hlassert(p1->winding->numpoints >= 3);
  742.         
  743.         // Check to make sure all the points on the other leaf are in front of the portal plane
  744.         for(k = 0, t = leaf2->portals[0]; k < leaf2->numportals; k++, t++)
  745.         {
  746.             for(l = 0; l < t->winding->numpoints; l++)
  747.             {
  748.                 check_dist = DotProduct(t->winding->points[l], p1->plane.normal) - p1->plane.dist;
  749.                 
  750.                 // We make the assumption that all portals face away from their parent leaf
  751.                 if(check_dist < -ON_EPSILON)
  752.                     goto PostLoop;
  753.             }
  754.         }
  755.  
  756. PostLoop:
  757.         // If we didn't check all the leaf2 portals, then this leaf1 portal doesn't work        
  758.         if(k < leaf2->numportals)
  759.             continue;
  760.  
  761.         // If we reach this point, we found a good portal
  762.         return p1;
  763.     }
  764.  
  765.     // Didn't find any
  766.     return NULL;
  767. }
  768.  
  769. // AJM: MVD
  770. // =====================================================================================
  771. //  MakeSplitPortalList
  772. //      This function returns a portal on leaf1 that sucessfully seperates leaf1
  773. //      and leaf2
  774. // =====================================================================================
  775. static void        MakeSplitPortalList(leaf_t *leaf1, leaf_t *leaf2, portal_t **portals, int *num_portals)
  776. {
  777.     int i, k, l;
  778.  
  779.     portal_t    *p1;
  780.     portal_t    *t;
  781.  
  782.     *num_portals = 0;
  783.  
  784.     float check_dist;
  785.  
  786.     portal_t p_list[MAX_PORTALS_ON_LEAF];
  787.     int c_portal = 0;
  788.  
  789.     if(*portals)
  790.         delete [] *portals;
  791.  
  792.     for(i = 0, p1 = leaf1->portals[0]; i < leaf1->numportals; i++, p1++)
  793.     {
  794.         hlassert(p1->winding->numpoints >= 3);
  795.         
  796.         // Check to make sure all the points on the other leaf are in front of the portal plane
  797.         for(k = 0, t = leaf2->portals[0]; k < leaf2->numportals; k++, t++)
  798.         {
  799.             for(l = 0; l < t->winding->numpoints; l++)
  800.             {
  801.                 check_dist = DotProduct(t->winding->points[l], p1->plane.normal) - p1->plane.dist;
  802.                 
  803.                 // We make the assumption that all portals face away from their parent leaf
  804.                 if(check_dist < -ON_EPSILON)
  805.                     goto PostLoop;
  806.             }
  807.         }
  808.  
  809. PostLoop:
  810.         // If we didn't check all the leaf2 portals, then this leaf1 portal doesn't work        
  811.         if(k < leaf2->numportals)
  812.             continue;
  813.  
  814.         // If we reach this point, we found a good portal
  815.         memcpy(&p_list[c_portal++], p1, sizeof(portal_t));
  816.  
  817.         if(c_portal >= MAX_PORTALS_ON_LEAF)
  818.             Error("c_portal > MAX_PORTALS_ON_LEAF");
  819.     }
  820.  
  821.     if(!c_portal)
  822.         return;
  823.  
  824.     *num_portals = c_portal;
  825.  
  826.     *portals = new portal_t[c_portal];
  827.     memcpy(*portals, p_list, c_portal * sizeof(portal_t));
  828. }
  829.  
  830. // AJM: MVD
  831. // =====================================================================================
  832. //  DisjointLeafVis
  833. //      This function returns TRUE if neither leaf can see the other
  834. //      Returns FALSE otherwise
  835. // =====================================================================================
  836. static bool            DisjointLeafVis(int leaf1, int leaf2)
  837. {
  838.     leaf_t *l = g_leafs + leaf1;
  839.     leaf_t *tl = g_leafs + leaf2;
  840.  
  841.     const unsigned offset_l = leaf1 >> 3;
  842.     const unsigned bit_l = (1 << (leaf1 & 7));
  843.  
  844.     const unsigned offset_tl = leaf2 >> 3;
  845.     const unsigned bit_tl = (1 << (leaf2 & 7));
  846.  
  847.     for(int k = 0; k < l->numportals; k++)
  848.     {
  849.         for(int m = 0; m < tl->numportals; m++)
  850.         {
  851.             if(l->portals[k]->mightsee[offset_tl] & bit_tl)
  852.                 goto RetFalse;
  853.             if(tl->portals[m]->mightsee[offset_l] & bit_l)
  854.                 goto RetFalse;
  855.  
  856.             if(l->portals[k]->status != stat_none)
  857.             {
  858.                 if(l->portals[k]->visbits[offset_tl] & bit_tl)
  859.                     goto RetFalse;
  860.             }
  861.             if(tl->portals[m]->status != stat_none)
  862.             {
  863.                 if(tl->portals[m]->visbits[offset_l] & bit_l)
  864.                     goto RetFalse;
  865.             }
  866.         }
  867.     }
  868.  
  869.     return true;
  870.  
  871. RetFalse:
  872.     return false;
  873. }
  874.  
  875. // AJM: MVD
  876. // =====================================================================================
  877. //  GetPortalBounds
  878. //      This function take a portal and finds its bounds
  879. //      parallel to the normal of the portal.  They will face inwards
  880. // =====================================================================================
  881. static void            GetPortalBounds(portal_t *p, plane_t **bounds)
  882. {
  883.     int i;
  884.     vec3_t vec1, vec2;
  885.  
  886.     hlassert(p->winding->numpoints >= 3);
  887.  
  888.     if(*bounds)
  889.         delete [] *bounds;
  890.  
  891.     *bounds = new plane_t[p->winding->numpoints];
  892.  
  893.     // Loop through each set of points and create a plane boundary for each
  894.     for(i = 0; i < p->winding->numpoints; i++)
  895.     {
  896.         VectorSubtract(p->winding->points[(i + 1) % p->winding->numpoints],p->winding->points[i],vec1);
  897.  
  898.         // Create inward normal for this boundary
  899.         CrossProduct(p->plane.normal, vec1, vec2);
  900.         VectorNormalize(vec2);
  901.  
  902.         VectorCopy(vec2, (*bounds)[i].normal);
  903.         (*bounds)[i].dist = DotProduct(p->winding->points[i], vec2);
  904.     }
  905. }
  906.  
  907. // AJM: MVD
  908. // =====================================================================================
  909. //  ClipWindingsToBounds
  910. //      clips all the windings with all the planes (including original face) and outputs 
  911. //      what's left int "out"
  912. // =====================================================================================
  913. static void            ClipWindingsToBounds(winding_t *windings, int numwindings, plane_t *bounds, int numbounds, plane_t &original_plane, winding_t **out, int &num_out)
  914. {
  915.     hlassert(windings);
  916.     hlassert(bounds);
  917.  
  918.     winding_t out_windings[MAX_PORTALS_ON_LEAF];
  919.     num_out = 0;
  920.  
  921.     int h, i;
  922.  
  923.     *out = NULL;
  924.  
  925.     Winding wind;
  926.  
  927.     for(h = 0; h < numwindings; h++)
  928.     {                    
  929.         // For each winding...
  930.         // Create a winding with CWinding
  931.  
  932.         wind.initFromPoints(windings[h].points, windings[h].numpoints);
  933.  
  934.         // Clip winding to original plane
  935.         wind.Chop(original_plane.normal, original_plane.dist);
  936.  
  937.         for(i = 0; i < numbounds, wind.Valid(); i++)
  938.         {
  939.             // For each bound...
  940.             // Chop the winding to the bounds
  941.             wind.Chop(bounds[i].normal, bounds[i].dist);
  942.         }
  943.         
  944.         if(wind.Valid())
  945.         {
  946.             // We have a valid winding, copy to array
  947.             wind.CopyPoints(&out_windings[num_out].points[0], out_windings[num_out].numpoints);
  948.  
  949.             num_out++;
  950.         }
  951.     }
  952.  
  953.     if(!num_out)        // Everything was clipped away
  954.         return;
  955.  
  956.     // Otherwise, create out
  957.     *out = new winding_t[num_out];
  958.  
  959.     memcpy(*out, out_windings, num_out * sizeof(winding_t));
  960. }
  961.  
  962. // AJM: MVD
  963. // =====================================================================================
  964. //  GenerateWindingList
  965. //      This function generates a list of windings for a leaf through its portals
  966. // =====================================================================================
  967. static void            GenerateWindingList(leaf_t *leaf, winding_t **winds)
  968. {
  969.     
  970.  
  971.     winding_t windings[MAX_PORTALS_ON_LEAF];
  972.     int numwinds = 0;
  973.  
  974.     int i;
  975.  
  976.     for(i = 0; i < leaf->numportals; i++)
  977.     {
  978.         memcpy(&windings[numwinds++], leaf->portals[i]->winding, sizeof(winding_t));
  979.     }
  980.  
  981.     if(!numwinds)
  982.         return;
  983.  
  984.     *winds = new winding_t[numwinds];
  985.     memcpy(*winds, &windings, sizeof(winding_t) * numwinds);
  986. }
  987.  
  988. // AJM: MVD
  989. // =====================================================================================
  990. //  CalcPortalBoundsAndClipPortals
  991. // =====================================================================================
  992. static void            CalcPortalBoundsAndClipPortals(portal_t *portal, leaf_t *leaf, winding_t **out, int &numout)
  993. {
  994.     plane_t *bounds = NULL;
  995.     winding_t *windings = NULL;
  996.  
  997.     GetPortalBounds(portal, &bounds);
  998.     GenerateWindingList(leaf, &windings);
  999.  
  1000.     ClipWindingsToBounds(windings, leaf->numportals, bounds, portal->winding->numpoints, portal->plane, out, numout);
  1001.  
  1002.     delete bounds;
  1003.     delete windings;
  1004. }
  1005.  
  1006. // AJM: MVD
  1007. // =====================================================================================
  1008. //  GetShortestDistance
  1009. //      Gets the shortest distance between both leaves
  1010. // =====================================================================================
  1011. static float        GetShortestDistance(leaf_t *leaf1, leaf_t *leaf2)
  1012. {
  1013.     winding_t *final = NULL;
  1014.     int num_finals = 0;
  1015.  
  1016.     int i, x, y;
  1017.     float check;
  1018.  
  1019.     for(i = 0; i < leaf1->numportals; i++)
  1020.     {
  1021.         CalcPortalBoundsAndClipPortals(leaf1->portals[i], leaf2, &final, num_finals);
  1022.  
  1023.         // Minimum point distance
  1024.         for(x = 0; x < num_finals; x++)
  1025.         {
  1026.             for(y = 0; y < final[x].numpoints; y++)
  1027.             {
  1028.                 check = DotProduct(leaf1->portals[i]->plane.normal, final[x].points[y]) - leaf1->portals[i]->plane.dist;
  1029.  
  1030.                 if(check <= g_maxdistance)
  1031.                     return check;
  1032.             }
  1033.         }
  1034.  
  1035.         delete final;
  1036.     }
  1037.  
  1038.     // Switch leaf 1 and 2
  1039.     for(i = 0; i < leaf2->numportals; i++)
  1040.     {
  1041.         CalcPortalBoundsAndClipPortals(leaf2->portals[i], leaf1, &final, num_finals);
  1042.  
  1043.         // Minimum point distance
  1044.         for(x = 0; x < num_finals; x++)
  1045.         {
  1046.             for(y = 0; y < final[x].numpoints; y++)
  1047.             {
  1048.                 check = DotProduct(leaf2->portals[i]->plane.normal, final[x].points[y]) - leaf2->portals[i]->plane.dist;
  1049.  
  1050.                 if(check <= g_maxdistance)
  1051.                     return check;
  1052.             }
  1053.         }
  1054.  
  1055.         delete final;
  1056.     }
  1057.  
  1058.     return 9E10;
  1059. }
  1060.  
  1061. // AJM: MVD
  1062. // =====================================================================================
  1063. //  CalcSplitsAndDotProducts
  1064. //      This function finds the splits of the leaf, and generates windings (if applicable)
  1065. // =====================================================================================
  1066. static float        CalcSplitsAndDotProducts(plane_t *org_split_plane, leaf_t *leaf1, leaf_t *leaf2, plane_t *bounds, int num_bounds)
  1067. {
  1068.     int i, j, k, l;
  1069.     
  1070.     portal_t *splits = NULL;
  1071.     int num_splits;
  1072.  
  1073.     float dist;
  1074.     float min_dist = 999999999.999;
  1075.  
  1076.     vec3_t i_points[MAX_POINTS_ON_FIXED_WINDING * MAX_PORTALS_ON_LEAF * 2];
  1077.     vec3_t delta;
  1078.     int num_points = 0;
  1079.  
  1080.     // First get splits
  1081.     MakeSplitPortalList(leaf1, leaf2, &splits, &num_splits);
  1082.  
  1083.     if(!num_splits)
  1084.         return min_dist;
  1085.  
  1086.     // If the number of splits = 1, then clip the plane using the boundary windings
  1087.     if(num_splits == 1)
  1088.     {
  1089.         Winding wind(splits[0].plane.normal, splits[0].plane.dist);
  1090.  
  1091.         for(i = 0;  i < num_bounds; i++)
  1092.         {
  1093.             wind.Chop(bounds[i].normal, bounds[i].dist);
  1094.         }
  1095.  
  1096.         // The wind is chopped - get closest dot product
  1097.         for(i = 0; i < wind.m_NumPoints; i++)
  1098.         {
  1099.             dist = DotProduct(wind.m_Points[i], org_split_plane->normal) - org_split_plane->dist;
  1100.  
  1101.             min_dist = min(min_dist, dist);
  1102.         }
  1103.  
  1104.         return min_dist;
  1105.     }
  1106.  
  1107.     // In this case, we have more than one split point, and we must calculate all intersections
  1108.     // Properties of convex objects allow us to assume that these intersections will be the closest
  1109.     // points to the other leaf, and our other checks before this eliminate exception cases
  1110.  
  1111.     // Loop through each split portal, and using an inside loop, loop through every OTHER split portal
  1112.     // Common portal points in more than one split portal are intersections!
  1113.     for(i = 0; i < num_splits; i++)
  1114.     {
  1115.         for(j = 0; j < num_splits; j++)
  1116.         {
  1117.             if(i == j)
  1118.             {
  1119.                 continue;
  1120.             }
  1121.  
  1122.             // Loop through each point on both portals
  1123.             for(k = 0; k < splits[i].winding->numpoints; k++)
  1124.             {
  1125.                 for(l = 0; l < splits[j].winding->numpoints; l++)
  1126.                 {
  1127.                     VectorSubtract(splits[i].winding->points[k], splits[j].winding->points[l], delta);
  1128.  
  1129.                     if(VectorLength(delta) < EQUAL_EPSILON)
  1130.                     {
  1131.                         memcpy(i_points[num_points++], splits[i].winding->points[k], sizeof(vec3_t));
  1132.                     }
  1133.                 }
  1134.             }
  1135.         }
  1136.     }
  1137.  
  1138.     // Loop through each intersection point and check
  1139.     for(i = 0; i < num_points; i++)
  1140.     {
  1141.         dist = DotProduct(i_points[i], org_split_plane->normal) - org_split_plane->dist;
  1142.  
  1143.         min_dist = min(min_dist, dist);
  1144.     }
  1145.  
  1146.     if(splits)
  1147.         delete [] splits;
  1148.  
  1149.     return min_dist;            
  1150. }
  1151.  
  1152. #endif // HLVIS_MAXDIST
  1153.  
  1154. // =====================================================================================
  1155. //  BasePortalVis
  1156. // =====================================================================================
  1157. void            BasePortalVis(int unused)
  1158. {
  1159.     int             i, j, k;
  1160.     portal_t*       tp;
  1161.     portal_t*       p;
  1162.     float           d;
  1163.     winding_t*      w;
  1164.     byte            portalsee[PORTALSEE_SIZE];
  1165.     const int       portalsize = (g_numportals * 2);
  1166.  
  1167. #ifdef ZHLT_NETVIS
  1168.     {
  1169.         i = unused;
  1170. #else
  1171.     while (1)
  1172.     {
  1173.         i = GetThreadWork();
  1174.         if (i == -1)
  1175.             break;
  1176. #endif
  1177.         p = g_portals + i;
  1178.  
  1179.         p->mightsee = (byte*)calloc(1, g_bitbytes);
  1180.  
  1181.         memset(portalsee, 0, portalsize);
  1182.  
  1183. #if ZHLT_ZONES
  1184.         UINT32 zone = p->zone;
  1185. #endif
  1186.  
  1187.         for (j = 0, tp = g_portals; j < portalsize; j++, tp++)
  1188.         {
  1189.             if (j == i)
  1190.             {
  1191.                 continue;
  1192.             }
  1193. #if ZHLT_ZONES
  1194.             if (g_Zones->check(zone, tp->zone))
  1195.             {
  1196.                 continue;
  1197.             }
  1198. #endif
  1199.  
  1200.             w = tp->winding;
  1201.             for (k = 0; k < w->numpoints; k++)
  1202.             {
  1203.                 d = DotProduct(w->points[k], p->plane.normal) - p->plane.dist;
  1204.                 if (d > ON_EPSILON)
  1205.                 {
  1206.                     break;
  1207.                 }
  1208.             }
  1209.             if (k == w->numpoints)
  1210.             {
  1211.                 continue;                                  // no points on front
  1212.             }
  1213.  
  1214.  
  1215.             w = p->winding;
  1216.             for (k = 0; k < w->numpoints; k++)
  1217.             {
  1218.                 d = DotProduct(w->points[k], tp->plane.normal) - tp->plane.dist;
  1219.                 if (d < -ON_EPSILON)
  1220.                 {
  1221.                     break;
  1222.                 }
  1223.             }
  1224.             if (k == w->numpoints)
  1225.             {
  1226.                 continue;                                  // no points on front
  1227.             }
  1228.  
  1229.  
  1230.             portalsee[j] = 1;
  1231.         }
  1232.  
  1233.         SimpleFlood(p->mightsee, p->leaf, portalsee, &p->nummightsee);
  1234.         Verbose("portal:%4i  nummightsee:%4i \n", i, p->nummightsee);
  1235.     }
  1236. }
  1237.  
  1238. #ifdef HLVIS_MAXDIST
  1239. // AJM: MVD
  1240. // =====================================================================================
  1241. //  MaxDistVis
  1242. // =====================================================================================
  1243. void    MaxDistVis(int unused)
  1244. {
  1245.     int i, j, k, m;
  1246.     int a, b, c, d;
  1247.     leaf_t    *l;
  1248.     leaf_t    *tl;
  1249.     plane_t    *boundary = NULL;
  1250.     vec3_t delta;
  1251.  
  1252.     float new_dist;
  1253.  
  1254.     unsigned offset_l;
  1255.     unsigned bit_l;
  1256.  
  1257.     unsigned offset_tl;
  1258.     unsigned bit_tl;
  1259.     
  1260.     while(1)
  1261.     {
  1262.         i = GetThreadWork();
  1263.         if (i == -1)
  1264.             break;
  1265.  
  1266.         l = &g_leafs[i];
  1267.  
  1268.         for(j = i + 1, tl = g_leafs + j; j < g_portalleafs; j++, tl++)
  1269.         {
  1270.             if(j == i)        // Ideally, should never be true
  1271.             {
  1272.                 continue;
  1273.             }
  1274.  
  1275.             // If they already can't see each other, no use checking
  1276.             if(DisjointLeafVis(i, j))
  1277.             {
  1278.                 continue;
  1279.             }
  1280.  
  1281.             new_dist = GetShortestDistance(l, tl);
  1282.  
  1283.             if(new_dist <= g_maxdistance)
  1284.                 continue;
  1285.  
  1286.             // Try out our NEW, IMPROVED ALGORITHM!!!!
  1287.             
  1288.             // Get a portal on Leaf 1 that completely seperates the two leafs
  1289.             /*split = GetSplitPortal(l, tl);
  1290.  
  1291.             if(!split)
  1292.                 continue;
  1293.  
  1294.             // We have a split, so create the bounds
  1295.             GetPortalBounds(split, &boundary);
  1296.  
  1297.             // Now get the dot product for all points on the other leaf
  1298.             max_dist = 999999999.999;
  1299.  
  1300.             /// Do the first check if mode is >= 2
  1301.             if(g_mdmode >= 2)
  1302.             {
  1303.                 for(k = 0; k < tl->numportals; k++)
  1304.                 {
  1305.                     for(m = 0; m < tl->portals[k]->winding->numpoints; m++)
  1306.                     {
  1307.                         for(n = 0; n < split->winding->numpoints; n++) // numpoints of split portals = number of boundaries
  1308.                         {
  1309.                             dist = DotProduct(tl->portals[k]->winding->points[m], boundary[n].normal) - boundary[n].dist;
  1310.     
  1311.                             if(dist < -ON_EPSILON)
  1312.                             {
  1313.                                 // Outside boundaries
  1314.                                 //max_dot = MaxDotProduct(tl->portals[k]->winding->points[m], boundary, split->winding->numpoints);
  1315.  
  1316.                                 //max_dist = min(max_dist, max_dot);
  1317.  
  1318.                                 // Break so we don't do inside boundary check
  1319.                                 break;
  1320.                             }
  1321.                         }
  1322.                         if(n < split->winding->numpoints)
  1323.                             continue;
  1324.  
  1325.                         // We found a point that's inside all the boundries!
  1326.                         new_dist = DotProduct(tl->portals[k]->winding->points[m], split->plane.normal) - split->plane.dist;
  1327.  
  1328.                         max_dist = min(max_dist, new_dist);
  1329.                     }
  1330.                 }
  1331.             }
  1332.  
  1333.             // This is now a special check.  If Leaf 2 has a split plane, we generate a polygon by clipping the plane
  1334.             // with the borders.  We then get the minimum dot products.  If more than one split plane, use intersection.
  1335.             // Only do this is g_mdmode is 3
  1336.             if(g_mdmode >= 3)    // For future mode expansion
  1337.             {
  1338.                 new_dist = CalcSplitsAndDotProducts(&split->plane, tl, l, boundary, split->winding->numpoints);
  1339.  
  1340.                 max_dist = min(max_dist, new_dist);
  1341.             }*/
  1342.  
  1343.             // Third and final check.  If the whole of leaf2 is outside of leaf1 boundaries, this one will catch it
  1344.             // Basic "every point to every point" type of deal :)
  1345.             // This is done by default all the time
  1346.             for(a = 0; a < l->numportals; a++)
  1347.             {
  1348.                 for(b = 0; b < tl->numportals; b++)
  1349.                 {
  1350.                     for(c = 0; c < l->portals[a]->winding->numpoints; c++)
  1351.                     {
  1352.                         for(d = 0; d < tl->portals[b]->winding->numpoints; d++)
  1353.                         {
  1354.                             VectorSubtract(l->portals[a]->winding->points[c], tl->portals[b]->winding->points[d], delta);
  1355.  
  1356.                             if(VectorLength(delta) <= g_maxdistance)
  1357.                                 goto NoWork;
  1358.                         }
  1359.                     }
  1360.                 }
  1361.             }
  1362.  
  1363.             offset_l = i >> 3;
  1364.             bit_l = (1 << (i & 7));
  1365.  
  1366.             offset_tl = j >> 3;
  1367.             bit_tl = (1 << (j & 7));
  1368.  
  1369.             for(k = 0; k < l->numportals; k++)
  1370.             {
  1371.                 for(m = 0; m < tl->numportals; m++)
  1372.                 {
  1373.                     if(l->portals[k]->status != stat_none)
  1374.                         l->portals[k]->visbits[offset_tl] &= ~bit_tl;
  1375.                     else
  1376.                         l->portals[k]->mightsee[offset_tl] &= ~bit_tl;
  1377.                     
  1378.                     if(tl->portals[m]->status != stat_none)
  1379.                         tl->portals[m]->visbits[offset_l] &= ~bit_l;
  1380.                     else
  1381.                         tl->portals[m]->mightsee[offset_l] &= ~bit_l;
  1382.                 }
  1383.             }
  1384.             
  1385. NoWork:
  1386.             continue;    // Hack to keep label from causing compile error
  1387.         }
  1388.     }
  1389.  
  1390.     // Release potential memory
  1391.     if(boundary)
  1392.         delete [] boundary;
  1393. }
  1394. #endif // HLVIS_MAXDIST
  1395.  
  1396. #ifdef SYSTEM_WIN32
  1397. #pragma warning(pop)
  1398. #endif
  1399.